{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Signature"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "license_cell",
      "metadata": {
        "tags": [
          "remove-cell"
        ]
      },
      "source": [
        "GTSAM Copyright 2010-2022, Georgia Tech Research Corporation,\nAtlanta, Georgia 30332-0415\nAll Rights Reserved\n\nAuthors: Frank Dellaert, et al. (see THANKS for the full author list)\n\nSee LICENSE for the license information"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "<a href=\"https://colab.research.google.com/github/borglab/gtsam/blob/develop/gtsam/discrete/doc/Signature.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "tags": [
          "remove-cell"
        ]
      },
      "outputs": [],
      "source": [
        "try:\n",
        "    import google.colab\n",
        "    %pip install --quiet gtsam\n",
        "except ImportError:\n",
        "    pass  # Not running on Colab, do nothing"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "A `gtsam.Signature` is a helper object used to construct discrete conditionals (`DiscreteConditional` and `DiscreteDistribution`). It provides a compact and readable way to define a conditional probability table (CPT) along with the variables involved.\n",
        "\n",
        "While in C++ `Signature` enables expressive syntax like `(D|E,B) = \"9/1 2/8 3/7 1/9\"`, this syntax does not translate directly to Python. However, the core concept of specifying a key, its parents, and a CPT string is central to how discrete factors are created in the Python wrapper.\n",
        "\n",
        "This notebook explains the CPT string format and shows how to use the signature concept to easily create discrete conditionals and Bayes nets in Python."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [],
      "source": [
        "import gtsam\n",
        "from gtsam.symbol_shorthand import A, B, C"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## The Signature CPT String Format\n",
        "\n",
        "The power of the signature concept comes from its compact CPT string representation.\n",
        "\n",
        "- **Parent Assignment Order:** The table is specified in an order where the parents' assignments count up like a binary number. The last parent in the list varies fastest. For parents `A, B`, the order is `A=0,B=0`, then `A=0,B=1`, then `A=1,B=0`, then `A=1,B=1`.\n",
        "- **Child Probabilities:** For each parent assignment, you provide the probabilities for the child variable's outcomes. These are often written as ratios separated by a `/`. For a binary child, `\"9/1\"` is shorthand for `P(Child=0)=0.9, P(Child=1)=0.1`. The values are automatically normalized.\n",
        "\n",
        "**Example:** For $P(C | A, B)$ where A, B, and C are binary, the string `\"1/9 2/8 3/7 4/6\"` corresponds to:\n",
        "1.  `A=0, B=0`: $P(C=0)=0.1, P(C=1)=0.9$\n",
        "2.  `A=0, B=1`: $P(C=0)=0.2, P(C=1)=0.8$\n",
        "3.  `A=1, B=0`: $P(C=0)=0.3, P(C=1)=0.7$\n",
        "4.  `A=1, B=1`: $P(C=0)=0.4, P(C=1)=0.6$"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Using the Signature Concept in Python\n",
        "\n",
        "The most common and direct way to use this concept in Python is to pass the signature components (key, parents, CPT string) directly into the `DiscreteConditional` or `DiscreteDistribution` constructors. This bypasses the need to create an explicit `Signature` object."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "--- P(A) ---\n"
          ]
        },
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<p>  <i>P(a0):</i></p>\n",
              "<div>\n",
              "<table class='DecisionTreeFactor'>\n",
              "  <thead>\n",
              "    <tr><th>a0</th><th>value</th></tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr><th>0</th><td>0.8</td></tr>\n",
              "    <tr><th>1</th><td>0.2</td></tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/markdown": [
              " *P(a0):*\n",
              "\n",
              "|a0|value|\n",
              "|:-:|:-:|\n",
              "|0|0.8|\n",
              "|1|0.2|\n"
            ],
            "text/plain": [
              "Discrete Prior\n",
              " P( a0 ):\n",
              " Choice(a0) \n",
              " 0 Leaf  0.8\n",
              " 1 Leaf  0.2\n"
            ]
          },
          "execution_count": 6,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Define keys for three binary variables\n",
        "KeyA = (A(0), 2)\n",
        "KeyB = (B(0), 2)\n",
        "KeyC = (C(0), 2)\n",
        "\n",
        "# Create a prior (no parents) P(A)\n",
        "# This is the signature: A % \"8/2\"\n",
        "p_A = gtsam.DiscreteDistribution(KeyA, \"8/2\")\n",
        "p_A"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 8,
      "id": "1f61e61e",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<p>  <i>P(b0|a0):</i></p>\n",
              "<table class='DiscreteConditional'>\n",
              "  <thead>\n",
              "    <tr><th><i>a0</i></th><th>0</th><th>1</th></tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr><th>0</th><td>0.1</td><td>0.9</td></tr>\n",
              "    <tr><th>1</th><td>0.6</td><td>0.4</td></tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/markdown": [
              " *P(b0|a0):*\n",
              "\n",
              "|*a0*|0|1|\n",
              "|:-:|:-:|:-:|\n",
              "|0|0.1|0.9|\n",
              "|1|0.6|0.4|\n"
            ],
            "text/plain": [
              "Discrete Conditional\n",
              " P( b0 | a0 ):\n",
              " Choice(b0) \n",
              " 0 Choice(a0) \n",
              " 0 0 Leaf  0.1\n",
              " 0 1 Leaf  0.6\n",
              " 1 Choice(a0) \n",
              " 1 0 Leaf  0.9\n",
              " 1 1 Leaf  0.4\n"
            ]
          },
          "execution_count": 8,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Create a conditional P(B|A)\n",
        "# Signature: (B|A) = \"1/9 6/4\"\n",
        "# Parent A=0: P(B)=0.1/0.9; Parent A=1: P(B)=0.6/0.4\n",
        "p_B_given_A = gtsam.DiscreteConditional(KeyB, [KeyA], \"1/9 6/4\")\n",
        "p_B_given_A"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 10,
      "id": "8fbf55c5",
      "metadata": {},
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div><p><tt>DiscreteBayesNet</tt> of size 2</p><div>\n",
              "<p>  <i>P(a0):</i></p>\n",
              "<div>\n",
              "<table class='DecisionTreeFactor'>\n",
              "  <thead>\n",
              "    <tr><th>a0</th><th>value</th></tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr><th>0</th><td>0.8</td></tr>\n",
              "    <tr><th>1</th><td>0.2</td></tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n",
              "<div>\n",
              "<p>  <i>P(b0|a0):</i></p>\n",
              "<table class='DiscreteConditional'>\n",
              "  <thead>\n",
              "    <tr><th><i>a0</i></th><th>0</th><th>1</th></tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr><th>0</th><td>0.1</td><td>0.9</td></tr>\n",
              "    <tr><th>1</th><td>0.6</td><td>0.4</td></tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>\n"
            ],
            "text/markdown": [
              "`DiscreteBayesNet` of size 2\n",
              "\n",
              " *P(a0):*\n",
              "\n",
              "|a0|value|\n",
              "|:-:|:-:|\n",
              "|0|0.8|\n",
              "|1|0.2|\n",
              "\n",
              " *P(b0|a0):*\n",
              "\n",
              "|*a0*|0|1|\n",
              "|:-:|:-:|:-:|\n",
              "|0|0.1|0.9|\n",
              "|1|0.6|0.4|\n",
              "\n"
            ],
            "text/plain": [
              "DiscreteBayesNet\n",
              " \n",
              "size: 2\n",
              "conditional 0:  P( a0 ):\n",
              " Choice(a0) \n",
              " 0 Leaf  0.8\n",
              " 1 Leaf  0.2\n",
              "\n",
              "conditional 1:  P( b0 | a0 ):\n",
              " Choice(b0) \n",
              " 0 Choice(a0) \n",
              " 0 0 Leaf  0.1\n",
              " 0 1 Leaf  0.6\n",
              " 1 Choice(a0) \n",
              " 1 0 Leaf  0.9\n",
              " 1 1 Leaf  0.4\n"
            ]
          },
          "execution_count": 10,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# The constructors for factor graph and Bayes nets are also overloaded\n",
        "dbn = gtsam.DiscreteBayesNet()\n",
        "dbn.add(KeyA, \"8/2\")\n",
        "dbn.add(KeyB, [KeyA], \"1/9 6/4\")\n",
        "dbn"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "py312",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.12.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}